package com.pefis.natives;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Iterator;

/*
 * Ast2600Device.java
 * This file is part of Ast2600Device
 *
 * Copyright (C) 2017 - Newpub
 *
 * Ast2600Device is for PEFIS device reading fp image.
 */

import android.app.Activity;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Build;
import android.util.Log;


public class Ast2600Device {

    public final static String TAG = "PUB";
    protected static final String ACTION_USB_PERMISSION = "ch.serverbox.android.USB";
    private static int m_nEPInSize, m_nEPOutSize;
    private static byte[] m_abyTransferBuf;
    private static boolean m_bInit = false;
    private static UsbDeviceConnection m_usbConn = null;
    private static UsbEndpoint m_epIN = null;
    private static UsbEndpoint m_epOUT = null;
    private final Context mApplicationContext;
    private final UsbManager mUsbManager;
    private final int VID;
    private final int PID;
    private final IUsbConnState mConnectionHandler;

    public int m_TryConnect = 0;
    private UsbDevice m_usbDevice;
    private UsbInterface m_usbIf = null;
    // END MAIN LOOP
    private BroadcastReceiver mPermissionReceiver = new PermissionReceiver(
            new IPermissionListener() {
                @Override
                public void onPermissionDenied(UsbDevice d) {
                    l("Permission denied on " + d.getDeviceId());
                }
            });

    /**
     * Activity is needed for onResult
     *
     * @param parentActivity
     */
    public Ast2600Device(Activity parentActivity, IUsbConnState connectionHandler, int vid, int pid) {
        mConnectionHandler = connectionHandler;
        mApplicationContext = parentActivity.getApplicationContext();
        mUsbManager = (UsbManager) mApplicationContext.getSystemService(Context.USB_SERVICE);
        VID = vid;
        PID = pid;

       /* final TelephonyManager tm = (TelephonyManager) mApplicationContext
                .getSystemService(Context.TELEPHONY_SERVICE);
        final String tmDevice, tmSerial, androidId;
        tmDevice = "" + tm.getDeviceId();
        Log.e("DeviceIMEI", "" + tmDevice);
        tmSerial = "" + tm.getSimSerialNumber();
        Log.e("[simcard] ", "" + tmSerial);
        androidId = "" + android.provider.Settings.Secure.getString(mApplicationContext.getContentResolver(),
                android.provider.Settings.Secure.ANDROID_ID);
        Log.e("androidId CDMA devices", "" + androidId);
        UUID deviceUuid = new UUID(androidId.hashCode(),
                ((long) tmDevice.hashCode() << 32) | tmSerial.hashCode());
        String deviceId = deviceUuid.toString();
        Log.e("deviceIdUUID ", "" + deviceId);
        String deviceModelName = android.os.Build.MODEL;
        Log.e("Model Name", "" + deviceModelName);
        String deviceUSER = android.os.Build.USER;
        Log.e("Name USER", "" + deviceUSER);
        String devicePRODUCT = android.os.Build.PRODUCT;
        Log.e("PRODUCT", "" + devicePRODUCT);
        String deviceHARDWARE = android.os.Build.HARDWARE;
        Log.e("HARDWARE", "" + deviceHARDWARE);
        String deviceBRAND = android.os.Build.BRAND;
        Log.e("BRAND", "" + deviceBRAND);
        String myVersion = android.os.Build.VERSION.RELEASE;
        Log.e("VERSION.RELEASE", "" + myVersion);
        int sdkVersion = android.os.Build.VERSION.SDK_INT;
        Log.e("VERSION.SDK_INT", "" + sdkVersion);
        Log.e("Last UUID",""+ generateDeviceIdentifier(mApplicationContext));*/
        m_abyTransferBuf = new byte[512];
        //init();
    }

    public static String generateDeviceIdentifier(Context context) {

        String pseudoId = "35" +
                Build.BOARD.length() % 10 +
                Build.BRAND.length() % 10 +
                Build.CPU_ABI.length() % 10 +
                Build.DEVICE.length() % 10 +
                Build.DISPLAY.length() % 10 +
                Build.HOST.length() % 10 +
                Build.ID.length() % 10 +
                Build.MANUFACTURER.length() % 10 +
                Build.MODEL.length() % 10 +
                Build.PRODUCT.length() % 10 +
                Build.TAGS.length() % 10 +
                Build.TYPE.length() % 10 +
                Build.USER.length() % 10;

        String sid = Build.SERIAL;
        Log.e("T","sid = "+sid);
        String androidId = android.provider.Settings.Secure.getString(context.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);

        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        String btId = "";

        if (bluetoothAdapter != null) {
            btId = bluetoothAdapter.getAddress();
        }

        String longId = pseudoId + androidId + Build.SERIAL;
        String mac = getMacAddress();

        Log.e("T","mac = "+mac);

        Log.e("T","pseudoId="+pseudoId+" ,androidId="+androidId+" btId="+btId+" longId="+longId);
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.update(longId.getBytes(), 0, longId.length());

            // get md5 bytes
            byte md5Bytes[] = messageDigest.digest();

            // creating a hex string
            String identifier = "";

            for (byte md5Byte : md5Bytes) {
                int b = (0xFF & md5Byte);

                // if it is a single digit, make sure it have 0 in front (proper padding)
                if (b <= 0xF) {
                    identifier += "0";
                }

                // add number to string
                identifier += Integer.toHexString(b);
            }

            // hex string to uppercase
            identifier = identifier.toUpperCase();
            return identifier;
        } catch (Exception e) {
            Log.e("TAG", e.toString());
        }
        return "";
    }



    public static String loadFileAsString(String filePath) throws IOException{
        StringBuffer fileData = new StringBuffer(1000);
        BufferedReader reader = new BufferedReader(new FileReader(filePath));
        char[] buf = new char[1024];
        int numRead=0;
        while((numRead=reader.read(buf)) != -1){
            String readData = String.valueOf(buf, 0, numRead);
            fileData.append(readData);
        }
        reader.close();
        return fileData.toString();
    }

    /*
     * Get the STB MacAddress
     */
    public static String getMacAddress(){
        try {
            return loadFileAsString("/sys/class/net/eth0/address")
                    .toUpperCase().substring(0, 17);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static int UsbBulkSend(byte[] pBuf, int nLen, int nTimeOut) {
        int numBytesWrite, remaindBytes, offset = 0;
        byte[] mWriteBuffer = new byte[nLen];
        remaindBytes = nLen;

        while (remaindBytes > 0) {

            System.arraycopy(pBuf, offset, mWriteBuffer, 0, remaindBytes);

            numBytesWrite = m_usbConn.bulkTransfer(m_epOUT, mWriteBuffer, remaindBytes, nTimeOut);
            if (numBytesWrite < 0) {
                m_bInit = false;
                return -1;
            }
            remaindBytes -= numBytesWrite;

            offset += numBytesWrite;
        }
        return 0;
    }

    public static int UsbBulkReceive(byte[] pBuf, int nLen, int nTimeOut) {
        int numBytesRead, remaindBytes, offset = 0;
        byte[] mReaderBuffer = new byte[nLen];
        remaindBytes = nLen;

        while (remaindBytes > 0) {

            numBytesRead = m_usbConn.bulkTransfer(m_epIN, mReaderBuffer, remaindBytes, nTimeOut);
            if (numBytesRead < 0) {
                m_bInit = false;
                return -1;
            }
            remaindBytes -= numBytesRead;
            System.arraycopy(mReaderBuffer, 0, pBuf, offset, numBytesRead);
            offset += numBytesRead;
        }

        return 0;
    }

    public void init() {
        enumerate(new IPermissionListener() {
            @Override
            public void onPermissionDenied(UsbDevice d) {
                UsbManager usbman = (UsbManager) mApplicationContext.getSystemService(Context.USB_SERVICE);
                PendingIntent pi = PendingIntent.getBroadcast(mApplicationContext, 0, new Intent(ACTION_USB_PERMISSION), 0);
                mApplicationContext.registerReceiver(mPermissionReceiver, new IntentFilter(ACTION_USB_PERMISSION));
                usbman.requestPermission(d, pi);
            }
        });
    }

    public void uninit() {
        if (m_usbConn != null) {
            m_usbConn.releaseInterface(m_usbIf);
            m_usbConn.close();
            m_usbConn = null;
            m_bInit = false;
        }

        stop();
    }

    public void stop() {
        try {
            mApplicationContext.unregisterReceiver(mPermissionReceiver);
        } catch (IllegalArgumentException e) {
        }
        ;//bravo
    }

    public boolean IsInit() {
        return m_bInit;
    }

    private void enumerate(IPermissionListener listener) {
        boolean bFound = false;
        l("enumerating");
        HashMap<String, UsbDevice> devlist = mUsbManager.getDeviceList();
        Iterator<UsbDevice> deviter = devlist.values().iterator();

        while (deviter.hasNext()) {
            UsbDevice d = deviter.next();
            l("Found device: " + String.format("%04X:%04X", d.getVendorId(), d.getProductId()));

            ////Toast.makeText(mApplicationContext, "Found device: " + String.format("%04X:%04X", d.getVendorId(), d.getProductId()), //Toast.LENGTH_SHORT).show();
            //Toast.makeText(mApplicationContext, "Found device: " + String.format("%04X:%04X", d.getVendorId(), d.getProductId()), //Toast.LENGTH_SHORT).show();

            if (d.getVendorId() == VID && d.getProductId() == PID) {
                bFound = true;
               // l("Device under: " + d.getDeviceName());
                if (!mUsbManager.hasPermission(d)) {
                    //Toast.makeText(mApplicationContext, "enumerate, hasPermission return false", //Toast.LENGTH_SHORT).show();
                    listener.onPermissionDenied(d);
                } else {
                    if (m_TryConnect > 0) {
                        //UsbManager usbman = (UsbManager) mApplicationContext.getSystemService(Context.USB_SERVICE);

                        listener.onPermissionDenied(d);
                    }
                    //Toast.makeText(mApplicationContext, "enumerate, GetConnInerface start", //Toast.LENGTH_SHORT).show();
                    //startHandler(d);
                    GetConnInerface(d);
                    //TestComm(d);
                    return;
                }
                break;
            }
        }
        if (bFound == false) {
            //Toast.makeText(mApplicationContext, "no more devices found", //Toast.LENGTH_SHORT).show();
            //DebugManage.WriteLog2("no more devices found");
            mConnectionHandler.onDeviceNotFound();
        }
    }

    private void GetConnInerface(UsbDevice dev) {
        int n;


        m_usbDevice = dev;
        try {
            m_usbConn = mUsbManager.openDevice(dev);
        } catch (Exception e) {
            return;
        }
        n = dev.getInterfaceCount();

        if (n <= 0)
            return;

        if (!m_usbConn.claimInterface(dev.getInterface(0), true)) {
            return;
        }
        m_usbConn.controlTransfer(0x40, 0, 0, 0, null, 0, 0);// reset
        // 0, 1, 0, null, 0,
        // 0);//clear Rx
        m_usbConn.controlTransfer(0x40, 0, 2, 0, null, 0, 0);// clear Tx
        m_usbConn.controlTransfer(0x40, 0x02, 0x0000, 0, null, 0, 0);// flow
        // control
        // none
        m_usbIf = dev.getInterface(0);

        n = m_usbIf.getEndpointCount();

        if (n < 2)
            return;

        for (int i = 0; i < n; i++) {
            if (m_usbIf.getEndpoint(i).getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                if (m_usbIf.getEndpoint(i).getDirection() == UsbConstants.USB_DIR_IN)
                    m_epIN = m_usbIf.getEndpoint(i);
                else
                    m_epOUT = m_usbIf.getEndpoint(i);
            }
        }

        m_nEPInSize = m_epIN.getMaxPacketSize();
        m_nEPOutSize = m_epOUT.getMaxPacketSize();
       // l("m_nEPInSize" + m_nEPInSize + "   m_nEPOutSize" + m_nEPOutSize);
        m_bInit = true;

        //Toast.makeText(mApplicationContext," m_bInit = " +m_bInit, //Toast.LENGTH_SHORT).show();
        mConnectionHandler.onUsbConnected();
    }

    private void l(Object msg) {
        Log.e(TAG, ">==< " + msg.toString() + " >==<");
    }

    private void e(Object msg) {
        Log.e(TAG, ">==< " + msg.toString() + " >==<");
    }

    private static interface IPermissionListener {
        void onPermissionDenied(UsbDevice d);
    }

    private class PermissionReceiver extends BroadcastReceiver {
        private final IPermissionListener mPermissionListener;

        public PermissionReceiver(IPermissionListener permissionListener) {
            mPermissionListener = permissionListener;
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            mApplicationContext.unregisterReceiver(this);
            if (intent.getAction().equals(ACTION_USB_PERMISSION)) {
                if (!intent.getBooleanExtra(
                        UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                    mPermissionListener.onPermissionDenied((UsbDevice) intent
                            .getParcelableExtra(UsbManager.EXTRA_DEVICE));

                    mConnectionHandler.onUsbPermissionDenied();
                } else {
                    l("Permission granted");
                    UsbDevice dev = (UsbDevice) intent
                            .getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (dev != null) {
                        if (dev.getVendorId() == VID
                                && dev.getProductId() == PID) {
                            GetConnInerface(dev);
                        }
                    } else {
                        mConnectionHandler.onDeviceNotFound();
                    }
                }
            }
        }
    }
}
